/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/

#include "flgrCoreMalloc.h"
#include "flgrCoreDispatch.h"
#include "flgrCoreDataIO.h"
#include "flgrCoreGeometry.h"
#include "flgrCoreVector.h"

/*!
 * \defgroup group_fulguro_core_geometry Geometry functions
 * \ingroup group_fulguro_core
 * \brief Main functions to draw geometric shapes in images
 * @{
 */


#define FLGR_MACRO_GEOMETRY_PARSE_STRING(function,...)			\
  FLGR_Ret ret;								\
  FLGR_Vector *vector_color;						\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  if(dat==NULL) {							\
    POST_ERROR("Null objects!\n");					\
    return FLGR_RET_NULL_OBJECT;					\
  }									\
									\
  vector_color = flgr_vector_create(dat->spp,dat->type);		\
									\
  if((ret=flgr_vector_import_string(vector_color, color))		\
     != FLGR_RET_OK) {							\
									\
    POST_ERROR("String is not valid ""%s""\n",color);			\
    flgr_vector_destroy(vector_color);					\
    return ret;								\
  }									\
									\
  ret = function##_ptr(__VA_ARGS__,vector_color);			\
									\
  flgr_vector_destroy(vector_color);					\
									\
  return ret



//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// 1D Geometry functions
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

#define FLGR_MACRO_DRAW_1D_LINE(dtype)				\
  int i;							\
								\
  FLGR_DECLARE_FUNCTION;					\
								\
  for(i=x ; i<x+length ; i++) {					\
    flgr1d_set_data_vector_##dtype(dat,i,color);		\
  }								\
								\
  return


void flgr1d_draw_line_fgBIT(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_1D_LINE(fgBIT);
}
void flgr1d_draw_line_fgUINT8(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_1D_LINE(fgUINT8);
}
void flgr1d_draw_line_fgUINT16(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_1D_LINE(fgUINT16);
}
void flgr1d_draw_line_fgUINT32(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_1D_LINE(fgUINT32);
}
void flgr1d_draw_line_fgINT8(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_1D_LINE(fgINT8);
}
void flgr1d_draw_line_fgINT16(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_1D_LINE(fgINT16);
}
void flgr1d_draw_line_fgINT32(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_1D_LINE(fgINT32);
}
void flgr1d_draw_line_fgFLOAT32(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_1D_LINE(fgFLOAT32);
}
void flgr1d_draw_line_fgFLOAT64(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_1D_LINE(fgFLOAT64);
}


//////////////////////////////////////////////////////////////////
/*! Draw a line in a FLGR_Data1D
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x      : position
 *  @param length : length
 *  @param color  : pointer to color (the type of variable pointed must fit with dat->type)
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_draw_line_ptr(FLGR_Data1D *dat, int x, int length, FLGR_Vector *color) {

  FLGR_DECLARE_FUNCTION;

  if(dat == NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  if(length<0) {
    POST_WARNING("length < 0, force it to zero!\n");
    length=0;
  }
  
  FLGR_DISPATCH_PROCEDURE(dat->type,flgr1d_draw_line,dat,x,length,color);
}


//////////////////////////////////////////////////////////////////
/*! Draw a line in a FLGR_Data1D
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x      : position
 *  @param length : length
 *  @param color  : color string
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_draw_line_str(FLGR_Data1D *dat, int x, int length, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr1d_draw_line,dat,x,length);
}





















//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// 2D Geometry functions
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

#define FLGR_MACRO_DRAW2D_POINT(dtype)					\
  FLGR_DECLARE_FUNCTION;						\
									\
  if(y<0) return;							\
  if(x<0) return;							\
  if(y>=dat->size_y) return;						\
  if(x>=dat->size_x)  return;						\
									\
  flgr2d_set_data_vector_##dtype(dat, y, x, color);			\
									\
  return

void flgr2d_draw_point_fgBIT(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW2D_POINT(fgBIT);
}
void flgr2d_draw_point_fgUINT8(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW2D_POINT(fgUINT8);
}
void flgr2d_draw_point_fgUINT16(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW2D_POINT(fgUINT16);
}
void flgr2d_draw_point_fgUINT32(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW2D_POINT(fgUINT32);
}
void flgr2d_draw_point_fgINT8(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW2D_POINT(fgINT8);
}
void flgr2d_draw_point_fgINT16(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW2D_POINT(fgINT16);
}
void flgr2d_draw_point_fgINT32(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW2D_POINT(fgINT32);
}
void flgr2d_draw_point_fgFLOAT32(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW2D_POINT(fgFLOAT32);
}
void flgr2d_draw_point_fgFLOAT64(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW2D_POINT(fgFLOAT64);
}

//////////////////////////////////////////////////////////////////
/*! Draw a point
 *  @param dat   : a pointer to FLGR_Data2D
 *  @param x     : an integer for row number
 *  @param y     : an integer for column number
 *  @param color : pointer to color (the type of variable pointed must fit with dat->type)
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_point_ptr(FLGR_Data2D *dat, int x, int y, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_point,dat,x,y,color);
}

//////////////////////////////////////////////////////////////////
/*! Draw a point
 *  @param dat   : a pointer to FLGR_Data2D
 *  @param x     : an integer for row number
 *  @param y     : an integer for column number
 *  @param color : string for color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_point_str(FLGR_Data2D *dat, int x, int y, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_point,dat,x,y);
}



#define FLGR_MACRO_DRAW_2D_HORZ_LINE(dtype)	\
  int i;					\
						\
  FLGR_DECLARE_FUNCTION;			\
						\
  for(i=x;i<x+size_x;i++) {			\
    flgr2d_draw_point_##dtype(dat,i,y,color);	\
  }						\
  return

void flgr2d_draw_horizontal_line_fgBIT(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_HORZ_LINE(fgBIT);
}
void flgr2d_draw_horizontal_line_fgUINT8(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_HORZ_LINE(fgUINT8);
}
void flgr2d_draw_horizontal_line_fgUINT16(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_HORZ_LINE(fgUINT16);
}
void flgr2d_draw_horizontal_line_fgUINT32(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_HORZ_LINE(fgUINT32);
}
void flgr2d_draw_horizontal_line_fgINT8(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_HORZ_LINE(fgINT8);
}
void flgr2d_draw_horizontal_line_fgINT16(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_HORZ_LINE(fgINT16);
}
void flgr2d_draw_horizontal_line_fgINT32(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_HORZ_LINE(fgINT32);
}
void flgr2d_draw_horizontal_line_fgFLOAT32(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_HORZ_LINE(fgFLOAT32);
}
void flgr2d_draw_horizontal_line_fgFLOAT64(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_HORZ_LINE(fgFLOAT64);
}

//////////////////////////////////////////////////////////////////
/*! Draw an horizontal line
 *  @param dat   : a pointer to FLGR_Data2D
 *  @param x     : an integer for row number
 *  @param y     : an integer for column number
 *  @param size_x : an integer for line size_x
 *  @param color : a pointer to color variable
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_horizontal_line_ptr(FLGR_Data2D *dat, int x, int y, int size_x, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }


  if(size_x<0) {
    POST_WARNING("size_x < 0, force it to zero!\n");
    size_x=0;
  }

  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_horizontal_line,dat,x,y,size_x,color);
}

//////////////////////////////////////////////////////////////////
/*! Draw an horizontal line
 *  @param dat   : a pointer to FLGR_Data2D
 *  @param x     : an integer for row number
 *  @param y     : an integer for column number
 *  @param size_x : an integer for line size_x
 *  @param color : a string for color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_horizontal_line_str(FLGR_Data2D *dat, int x, int y, int size_x, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_horizontal_line,dat,x,y,size_x);
}


#define FLGR_MACRO_DRAW_2D_VERT_LINE(dtype)	\
  int i;					\
  FLGR_DECLARE_FUNCTION;			\
						\
						\
  for(i=y;i<y+size_y;i++) {			\
    flgr2d_draw_point_##dtype(dat,x,i,color);	\
  }						\
  return

void flgr2d_draw_vertical_line_fgBIT(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_VERT_LINE(fgBIT);
}
void flgr2d_draw_vertical_line_fgUINT8(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_VERT_LINE(fgUINT8);
}
void flgr2d_draw_vertical_line_fgUINT16(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_VERT_LINE(fgUINT16);
}
void flgr2d_draw_vertical_line_fgUINT32(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_VERT_LINE(fgUINT32);
}
void flgr2d_draw_vertical_line_fgINT8(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_VERT_LINE(fgINT8);
}
void flgr2d_draw_vertical_line_fgINT16(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_VERT_LINE(fgINT16);
}
void flgr2d_draw_vertical_line_fgINT32(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_VERT_LINE(fgINT32);
}
void flgr2d_draw_vertical_line_fgFLOAT32(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_VERT_LINE(fgFLOAT32);
}
void flgr2d_draw_vertical_line_fgFLOAT64(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_VERT_LINE(fgFLOAT64);
}

//////////////////////////////////////////////////////////////////
/*! Draw a vertical line
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x      : an integer for row number
 *  @param y      : an integer for column number
 *  @param size_y : an integer for line size_y
 *  @param color  : a pointer to color variable
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_vertical_line_ptr(FLGR_Data2D *dat, int x, int y, int size_y, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(size_y<0) {
    POST_WARNING("size_y < 0, force it to zero!\n");
    size_y = 0;
  }  

  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_vertical_line,dat,x,y,size_y,color);
}



//////////////////////////////////////////////////////////////////
/*! Draw a vertical line
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x      : an integer for row number
 *  @param y      : an integer for column number
 *  @param size_y : an integer for line size_x
 *  @param color  : a string for color variable
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_vertical_line_str(FLGR_Data2D *dat, int x, int y, int size_y, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_vertical_line,dat,x,y,size_y);
}



void dataExchange(int* x, int* y)
{
  int t = *x;
  *x = *y;
  *y = t;
}


#define FLGR_MACRO_DRAW_2D_LINE(dtype)			\
  int d, dx, dy, aincr, bincr, xincr, yincr, x, y;	\
							\
  FLGR_DECLARE_FUNCTION;				\
							\
  if (abs(x2 - x1) < abs(y2 - y1)) {			\
    /* vertical axis */					\
							\
    if (y1 > y2) {					\
      dataExchange(&x1, &x2);				\
      dataExchange(&y1, &y2);				\
    }							\
							\
    xincr = x2 > x1 ? 1 : -1;				\
    dy = y2 - y1;					\
    dx = abs(x2 - x1);					\
    d = 2 * dx - dy;					\
    aincr = 2 * (dx - dy);				\
    bincr = 2 * dx;					\
    x = x1;						\
    y = y1;						\
							\
    flgr2d_draw_point_##dtype(dat,x,y,color);		\
							\
    for (y = y1+1; y <= y2; ++y) {			\
      if (d >= 0) {					\
	x += xincr;					\
	d += aincr;					\
      } else						\
	d += bincr;					\
							\
      flgr2d_draw_point_##dtype(dat,x,y,color);		\
    }							\
							\
  } else {						\
    /* horizontal axis */				\
							\
    if (x1 > x2) {					\
      dataExchange(&x1, &x2);				\
      dataExchange(&y1, &y2);				\
    }							\
							\
    yincr = y2 > y1 ? 1 : -1;				\
    dx = x2 - x1;					\
    dy = abs(y2 - y1);					\
    d = 2 * dy - dx;					\
    aincr = 2 * (dy - dx);				\
    bincr = 2 * dy;					\
    x = x1;						\
    y = y1;						\
							\
    flgr2d_draw_point_##dtype(dat,x,y,color);		\
							\
    for (x = x1+1; x <= x2; ++x) {			\
      if (d >= 0) {					\
	y += yincr;					\
	d += aincr;					\
      } else						\
	d += bincr;					\
							\
      flgr2d_draw_point_##dtype(dat,x,y,color);		\
    }							\
  }							\
  return



void flgr2d_draw_line_fgBIT(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_LINE(fgBIT);
}
void flgr2d_draw_line_fgUINT8(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_LINE(fgUINT8);
}
void flgr2d_draw_line_fgUINT16(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_LINE(fgUINT16);
}
void flgr2d_draw_line_fgUINT32(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_LINE(fgUINT32);
}
void flgr2d_draw_line_fgINT8(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_LINE(fgINT8);
}
void flgr2d_draw_line_fgINT16(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_LINE(fgINT16);
}
void flgr2d_draw_line_fgINT32(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_LINE(fgINT32);
}
void flgr2d_draw_line_fgFLOAT32(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_LINE(fgFLOAT32);
}
void flgr2d_draw_line_fgFLOAT64(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_LINE(fgFLOAT64);
}


//////////////////////////////////////////////////////////////////
/*! Draw a line
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x1     : an integer for first point row
 *  @param y1     : an integer for first point column
 *  @param x2     : an integer for second point row
 *  @param y2     : an integer for second point column
 *  @param color  : a pointer to the color variable
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_line_ptr(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_line,dat,x1,y1,x2,y2,color);
  
}

//////////////////////////////////////////////////////////////////
/*! Draw a line
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x1     : an integer for first point row
 *  @param y1     : an integer for first point column
 *  @param x2     : an integer for second point row
 *  @param y2     : an integer for second point column
 *  @param color  : a string for color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_line_str(FLGR_Data2D *dat, int x1, int y1, int x2, int y2, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_line,dat,x1,y1,x2,y2);
}



#define FLGR_MACRO_DRAW_2D_RECT(dtype)					\
  FLGR_DECLARE_FUNCTION;						\
									\
  flgr2d_draw_horizontal_line_##dtype(dat,x, y, size_x , color);	\
  flgr2d_draw_horizontal_line_##dtype(dat,x, y + size_y - 1, size_x,	\
				      color);				\
  flgr2d_draw_vertical_line_##dtype(dat,x, y + 1, size_y - 2, color);	\
  flgr2d_draw_vertical_line_##dtype(dat,x + size_x - 1, y + 1,		\
				    size_y - 2, color);			\
  return

void flgr2d_draw_rectangle_fgBIT(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_RECT(fgBIT);
}
void flgr2d_draw_rectangle_fgUINT8(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_RECT(fgUINT8);
}
void flgr2d_draw_rectangle_fgUINT16(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_RECT(fgUINT16);
}
void flgr2d_draw_rectangle_fgUINT32(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_RECT(fgUINT32);
}
void flgr2d_draw_rectangle_fgINT8(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_RECT(fgINT8);
}
void flgr2d_draw_rectangle_fgINT16(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_RECT(fgINT16);
}
void flgr2d_draw_rectangle_fgINT32(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_RECT(fgINT32);
}
void flgr2d_draw_rectangle_fgFLOAT32(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_RECT(fgFLOAT32);
}
void flgr2d_draw_rectangle_fgFLOAT64(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_RECT(fgFLOAT64);
}

//////////////////////////////////////////////////////////////////
/*! Draw a rectangle
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x      : an integer for upper left corner row
 *  @param y      : an integer for upper left corner column
 *  @param size_x  : an integer for rectangle size_x
 *  @param size_y : an integer for rectangle size_y
 *  @param color  : a pointer to color variable
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_rectangle_ptr(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }


  if(size_y<0) {
    POST_WARNING("size_y < 0, force it to zero!\n");
    size_y = 0;
  }  

  if(size_x<0) {
    POST_WARNING("size_x < 0, force it to zero!\n");
    size_x = 0;
  }

  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_rectangle,dat,x,y,size_x,size_y,color);

}


//////////////////////////////////////////////////////////////////
/*! Draw a rectangle
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x      : an integer for upper left corner row
 *  @param y      : an integer for upper left corner column
 *  @param size_x  : an integer for rectangle size_x
 *  @param size_y : an integer for rectangle size_y
 *  @param color  : a string for color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_rectangle_str(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_rectangle,dat,x,y,size_x,size_y);
}



#define FLGR_MACRO_DRAW_2D_FILLED_RECT(dtype)				\
  int i;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(i=y; i<y+size_y ; i++)						\
    flgr2d_draw_horizontal_line_##dtype(dat,x, i, size_x , color);	\
  return

void flgr2d_draw_filled_rectangle_fgBIT(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_FILLED_RECT(fgBIT);
}
void flgr2d_draw_filled_rectangle_fgUINT8(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_FILLED_RECT(fgUINT8);
}
void flgr2d_draw_filled_rectangle_fgUINT16(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_FILLED_RECT(fgUINT16);
}
void flgr2d_draw_filled_rectangle_fgUINT32(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_FILLED_RECT(fgUINT32);
}
void flgr2d_draw_filled_rectangle_fgINT8(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_FILLED_RECT(fgINT8);
}
void flgr2d_draw_filled_rectangle_fgINT16(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_FILLED_RECT(fgINT16);
}
void flgr2d_draw_filled_rectangle_fgINT32(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_FILLED_RECT(fgINT32);
}
void flgr2d_draw_filled_rectangle_fgFLOAT32(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_FILLED_RECT(fgFLOAT32);
}
void flgr2d_draw_filled_rectangle_fgFLOAT64(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_FILLED_RECT(fgFLOAT64);
}


//////////////////////////////////////////////////////////////////
/*! Draw a filled rectangle
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x      : an integer for upper left corner row
 *  @param y      : an integer for upper left corner column
 *  @param size_x  : an integer for rectangle size_x
 *  @param size_y : an integer for rectangle size_y
 *  @param color  : a pointer to color variable
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_filled_rectangle_ptr(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  
  if(size_y<0) {
    POST_WARNING("size_y < 0, force it to zero!\n");
    size_y = 0;
  }

  if(size_x<0) {
    POST_WARNING("size_x < 0, force it to zero!\n");
    size_x = 0;
  }

  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_filled_rectangle,dat,x,y,size_x,size_y,color);

}

//////////////////////////////////////////////////////////////////
/*! Draw a filled rectangle
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param x      : an integer for upper left corner row
 *  @param y      : an integer for upper left corner column
 *  @param size_x  : an integer for rectangle size_x
 *  @param size_y : an integer for rectangle size_y
 *  @param color  : a string for color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_filled_rectangle_str(FLGR_Data2D *dat, int x, int y, int size_x, int size_y, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_filled_rectangle,dat,x,y,size_x,size_y);
}



#define FLGR_MACRO_DRAW_2D_2D_CIRCLE(dtype)		\
  int d, y, x;						\
  FLGR_DECLARE_FUNCTION;				\
							\
							\
  d = 3 - (2 * radius);					\
  x = 0;						\
  y = radius;						\
							\
  while (y >= x) {					\
    if( (cy+y>=0) && (cy+y<dat->size_y) ) {		\
      if( (cx+x>=0) && (cx+x<dat->size_x) )		\
	flgr2d_draw_point_##dtype(dat,cx+x,cy+y,color);	\
      if( (cx-x>=0) && (cx-x<dat->size_x) )		\
	flgr2d_draw_point_##dtype(dat,cx-x,cy+y,color);	\
    }							\
							\
    if( (cy+x>=0) && (cy+x<dat->size_y) ) {		\
      if( (cx+y>=0) && (cx+y<dat->size_x) )		\
	flgr2d_draw_point_##dtype(dat,cx+y,cy+x,color);	\
      if( (cx-y>=0) && (cx-y<dat->size_x) )		\
	flgr2d_draw_point_##dtype(dat,cx-y,cy+x,color);	\
    }							\
							\
    if((cy-y>=0) && (cy-y<dat->size_y) ) {		\
      if( (cx+x>=0) && (cx+x<dat->size_x) )		\
	flgr2d_draw_point_##dtype(dat,cx+x,cy-y,color);	\
      if( (cx-x>=0) && (cx-x<dat->size_x) )		\
	flgr2d_draw_point_##dtype(dat,cx-x,cy-y,color);	\
    }							\
							\
    if((cy-x>=0) && (cy-x<dat->size_y) ) {		\
      if( (cx+y>=0) && (cx+y<dat->size_x) )		\
	flgr2d_draw_point_##dtype(dat,cx+y,cy-x,color);	\
      if( (cx-y>=0) && (cx-y<dat->size_x) )		\
	flgr2d_draw_point_##dtype(dat,cx-y,cy-x,color);	\
    }							\
							\
    if (d < 0)						\
      d = d + (4 * x) + 6;				\
    else {						\
      d = d + 4 * (x - y) + 10;				\
      y--;						\
    }							\
							\
    x++;						\
  }							\
  return

void flgr2d_draw_circle_fgBIT(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_CIRCLE(fgBIT);
}
void flgr2d_draw_circle_fgUINT8(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_CIRCLE(fgUINT8);
}
void flgr2d_draw_circle_fgUINT16(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_CIRCLE(fgUINT16);
}
void flgr2d_draw_circle_fgUINT32(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_CIRCLE(fgUINT32);
}
void flgr2d_draw_circle_fgINT8(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_CIRCLE(fgINT8);
}
void flgr2d_draw_circle_fgINT16(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_CIRCLE(fgINT16);
}
void flgr2d_draw_circle_fgINT32(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_CIRCLE(fgINT32);
}
void flgr2d_draw_circle_fgFLOAT32(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_CIRCLE(fgFLOAT32);
}
void flgr2d_draw_circle_fgFLOAT64(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_CIRCLE(fgFLOAT64);
}


//////////////////////////////////////////////////////////////////
/*! Draw a circle
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param cx     : an integer for circle center row
 *  @param cy     : an integer for circle center column
 *  @param radius : an integer for circle radius
 *  @param color  : a pointer to color variable
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_circle_ptr(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  
  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_circle,dat,cx,cy,radius,color);

}

//////////////////////////////////////////////////////////////////
/*! Draw a circle
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param cx     : an integer for circle center row
 *  @param cy     : an integer for circle center column
 *  @param radius : an integer for circle radius
 *  @param color  : a string for column
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_circle_str(FLGR_Data2D *dat, int cx, int cy, int radius, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_circle,dat,cx,cy,radius);
}




#define FLGR_MACRO_DRAW_2D_2D_DISC(dtype)				\
  int d, y, x;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  d = 3 - (2 * radius);							\
  x = 0;								\
  y = radius;								\
									\
  while (y >= x) {							\
    flgr2d_draw_horizontal_line_##dtype(dat, cx-x, cy-y, 2*x+1, color);	\
    flgr2d_draw_horizontal_line_##dtype(dat, cx-x, cy+y, 2*x+1, color);	\
    flgr2d_draw_horizontal_line_##dtype(dat, cx-y, cy-x, 2*y+1, color);	\
    flgr2d_draw_horizontal_line_##dtype(dat, cx-y, cy+x, 2*y+1, color);	\
									\
    if (d < 0)								\
      d = d + (4 * x) + 6;						\
    else {								\
      d = d + 4 * (x - y) + 10;						\
      y--;								\
    }									\
									\
    x++;								\
  }									\
  return


void flgr2d_draw_disc_fgBIT(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_DISC(fgBIT);
}
void flgr2d_draw_disc_fgUINT8(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_DISC(fgUINT8);
}
void flgr2d_draw_disc_fgUINT16(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_DISC(fgUINT16);
}
void flgr2d_draw_disc_fgUINT32(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_DISC(fgUINT32);
}
void flgr2d_draw_disc_fgINT8(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_DISC(fgINT8);
}
void flgr2d_draw_disc_fgINT16(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_DISC(fgINT16);
}
void flgr2d_draw_disc_fgINT32(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_DISC(fgINT32);
}
void flgr2d_draw_disc_fgFLOAT32(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_DISC(fgFLOAT32);
}
void flgr2d_draw_disc_fgFLOAT64(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_DISC(fgFLOAT64);
}

//////////////////////////////////////////////////////////////////
/*! Draw a disc
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param cx     : an integer for circle center row
 *  @param cy     : an integer for circle center column
 *  @param radius : an integer for circle radius
 *  @param color  : a pointer to the color variable
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_disc_ptr(FLGR_Data2D *dat, int cx, int cy, int radius, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  
  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_disc,dat,cx,cy,radius,color);
}


//////////////////////////////////////////////////////////////////
/*! Draw a disc
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param cx     : an integer for circle center row
 *  @param cy     : an integer for circle center column
 *  @param radius : an integer for circle radius
 *  @param color  : a string for color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_disc_str(FLGR_Data2D *dat, int cx, int cy, int radius, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_disc,dat,cx,cy,radius);
}



#define FLGR_MACRO_DRAW_2D_2D_ELLIPSE(dtype)			\
  /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */			\
  int x = 0, y = b;						\
  long a2 = (long)a*a, b2 = (long)b*b;				\
  long crit1 = -(a2/4 + a%2 + b2);				\
  long crit2 = -(b2/4 + b%2 + a2);				\
  long crit3 = -(b2/4 + b%2);					\
  long t = -a2*y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */		\
  long dxt = 2*b2*x, dyt = -2*a2*y;				\
  long d2xt = 2*b2, d2yt = 2*a2;				\
								\
  FLGR_DECLARE_FUNCTION;					\
								\
  while (y>=0 && x<=a) {					\
    flgr2d_draw_point_##dtype(dat, cx+x, cy+y,  color);		\
    if (x!=0 || y!=0)						\
      flgr2d_draw_point_##dtype(dat, cx-x, cy-y, color);	\
    if (x!=0 && y!=0) {						\
      flgr2d_draw_point_##dtype(dat, cx+x, cy-y, color);	\
      flgr2d_draw_point_##dtype(dat, cx-x, cy+y, color);	\
    }								\
    if (t + b2*x <= crit1 ||   /* e(x+1,y-1/2) <= 0 */		\
	t + a2*y <= crit3)     /* e(x+1/2,y) <= 0 */		\
      x++, dxt += d2xt, t += dxt;				\
    else if (t - a2*y > crit2) /* e(x+1/2,y-1) > 0 */		\
      y--, dyt += d2yt, t += dyt;				\
    else {							\
      x++, dxt += d2xt, t += dxt;				\
      y--, dyt += d2yt, t += dyt;				\
    }								\
  }								\
  return


void flgr2d_draw_ellipse_fgBIT(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_ELLIPSE(fgBIT);
}
void flgr2d_draw_ellipse_fgUINT8(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_ELLIPSE(fgUINT8);
}
void flgr2d_draw_ellipse_fgUINT16(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_ELLIPSE(fgUINT16);
}
void flgr2d_draw_ellipse_fgUINT32(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_ELLIPSE(fgUINT32);
}
void flgr2d_draw_ellipse_fgINT8(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_ELLIPSE(fgINT8);
}
void flgr2d_draw_ellipse_fgINT16(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_ELLIPSE(fgINT16);
}
void flgr2d_draw_ellipse_fgINT32(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_ELLIPSE(fgINT32);
}
void flgr2d_draw_ellipse_fgFLOAT32(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_ELLIPSE(fgFLOAT32);
}
void flgr2d_draw_ellipse_fgFLOAT64(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_ELLIPSE(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Draw an ellispse
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param cx     : an integer for circle center row
 *  @param cy     : an integer for circle center column
 *  @param a      : an integer for major axis
 *  @param b      : an integer for minor axis
 *  @param color  : a pointer to FLGR_Vector color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_ellipse_ptr(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  
  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_ellipse,dat,cx,cy,a,b,color);
}


//////////////////////////////////////////////////////////////////
/*! Draw a ellipse
 *  
 *  Ellipse drawing using McIlroy's Algorithm 
 *
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param cx     : an integer for circle center row
 *  @param cy     : an integer for circle center column
 *  @param a      : an integer for major axis
 *  @param b      : an integer for minor axis
 *  @param color  : a string for color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_ellipse_str(FLGR_Data2D *dat, int cx, int cy, int a, int b, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_ellipse,dat,cx,cy,a,b);
}










#define FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(dtype)			\
  /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */				\
  int x = 0, y = b;							\
  unsigned int width = 1;						\
  long a2 = (long)a*a, b2 = (long)b*b;					\
  long crit1 = -(a2/4 + a%2 + b2);					\
  long crit2 = -(b2/4 + b%2 + a2);					\
  long crit3 = -(b2/4 + b%2);						\
  long t = -a2*y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */			\
  long dxt = 2*b2*x, dyt = -2*a2*y;					\
  long d2xt = 2*b2, d2yt = 2*a2;					\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  while (y>=0 && x<=a) {						\
    if (t + b2*x <= crit1 ||     /* e(x+1,y-1/2) <= 0 */		\
	t + a2*y <= crit3) {     /* e(x+1/2,y) <= 0 */			\
      x++, dxt += d2xt, t += dxt;					\
      width += 2;							\
    }									\
    else if (t - a2*y > crit2) { /* e(x+1/2,y-1) > 0 */			\
      flgr2d_draw_horizontal_line_##dtype(dat,cx-x,cy-y,width,color);	\
      if (y!=0)								\
	flgr2d_draw_horizontal_line_##dtype(dat,cx-x,cy+y,width,color); \
      y--, dyt += d2yt, t += dyt;					\
    }									\
    else {								\
      flgr2d_draw_horizontal_line_##dtype(dat,cx-x,cy-y,width,color);	\
      if (y!=0)								\
	flgr2d_draw_horizontal_line_##dtype(dat,cx-x,cy+y,width,color); \
      x++, dxt += d2xt, t += dxt;					\
      y--, dyt += d2yt, t += dyt;					\
      width += 2;							\
    }									\
  }									\
  if (b == 0)								\
    flgr2d_draw_horizontal_line_##dtype(dat,cx-a, cy, 2*a+1,color);	\
  									\
  return


void flgr2d_draw_filled_ellipse_fgBIT(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(fgBIT);
}
void flgr2d_draw_filled_ellipse_fgUINT8(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(fgUINT8);
}
void flgr2d_draw_filled_ellipse_fgUINT16(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(fgUINT16);
}
void flgr2d_draw_filled_ellipse_fgUINT32(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(fgUINT32);
}
void flgr2d_draw_filled_ellipse_fgINT8(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(fgINT8);
}
void flgr2d_draw_filled_ellipse_fgINT16(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(fgINT16);
}
void flgr2d_draw_filled_ellipse_fgINT32(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(fgINT32);
}
void flgr2d_draw_filled_ellipse_fgFLOAT32(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(fgFLOAT32);
}
void flgr2d_draw_filled_ellipse_fgFLOAT64(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_MACRO_DRAW_2D_2D_FILLED_ELLIPSE(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Draw an ellispse
 *
 *  Ellipse drawing using McIlroy's Algorithm
 *
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param cx     : an integer for circle center row
 *  @param cy     : an integer for circle center column
 *  @param a      : an integer for major axis
 *  @param b      : an integer for minor axis
 *  @param color  : a pointer to FLGR_Vector color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_filled_ellipse_ptr(FLGR_Data2D *dat, int cx, int cy, int a, int b, FLGR_Vector *color) {
  FLGR_DECLARE_FUNCTION;

  if(dat==NULL) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  
  FLGR_DISPATCH_PROCEDURE(dat->type,flgr2d_draw_filled_ellipse,dat,cx,cy,a,b,color);
}


//////////////////////////////////////////////////////////////////
/*! Draw a filled_ellipse
 *  @param dat    : a pointer to FLGR_Data2D
 *  @param cx     : an integer for circle center row
 *  @param cy     : an integer for circle center column
 *  @param a      : an integer for major axis
 *  @param b      : an integer for minor axis
 *  @param color  : a string for color
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_draw_filled_ellipse_str(FLGR_Data2D *dat, int cx, int cy, int a, int b, char *color) {
  FLGR_MACRO_GEOMETRY_PARSE_STRING(flgr2d_draw_filled_ellipse,dat,cx,cy,a,b);
}




//! @} defgroup group_fulguro_core_geometry
